#pragma once

#include "common/common.h"

namespace PILO 
{
    namespace Core
    {
        namespace Thread 
        {
            inline INT32 AtomicIntegerSet(INT32* dest, INT32 value)
            {
                return AtomicIntegerSet32(dest, value);
            }
            inline INT64 AtomicIntegerSet(INT64* dest, INT64 value)
            {
                return AtomicIntegerSet64(dest, value);
            }

            inline INT32 AtomicIntegerFetchAdd(INT32* dest, INT32 value)
            {
                return AtomicIntegerFetchAdd32(dest, value);
            }
            inline INT32 AtomicIntegerFetchAdd(INT64* dest, INT64 value)
            {
                return AtomicIntegerFetchAdd32(dest, value);
            }

            inline INT32 AtomicIntegerAnd(INT32* dest, INT32 value)
            {
                return AtomicIntegerAnd32(dest, value);
            }
            inline INT64 AtomicIntegerAnd(INT64* dest, INT64 value)
            {
                return AtomicIntegerAnd64(dest, value);
            }

            inline INT32 AtomicIntegerXor(INT32* dest, INT32 value)
            {
                return AtomicIntegerXor32(dest, value);
            }
            inline INT64 AtomicIntegerXor(INT64* dest, INT64 value)
            {
                return AtomicIntegerXor64(dest, value);
            }

            inline INT32 AtomicIntegerOr(INT32* dest, INT32 value)
            {
                return AtomicIntegerOr32(dest, value);
            }
            inline INT64 AtomicIntegerOr(INT64* dest, INT64 value)
            {
                return AtomicIntegerOr64(dest, value);
            }

            inline INT32 AtomicIntegerCompareAndSet(INT32* dest, INT32 comparand, INT32 newValue)
            {
                return AtomicIntegerCompareAndSet32(dest, comparand, newValue);
            }
            inline INT64 AtomicIntegerCompareAndSet(INT64* dest, INT64 comparand, INT64 newValue)
            {
                return AtomicIntegerCompareAndSet64(dest, comparand, newValue);
            }

            class CAtomicInteger32
            {
            public:
                inline CAtomicInteger32() {}
                inline CAtomicInteger32(INT32 v) { _m_value = v; }

                // Non-atomic APIs
                inline bool operator==(INT32 value) const
                {
                    return _m_value == value;
                }

                inline bool operator!=(INT32 value) const
                {
                    return _m_value != value;
                }

                inline bool operator!() const
                {
                    return _m_value == 0;
                }

                inline operator INT32() const
                {
                    return _m_value;
                }

                inline CAtomicInteger32 &operator=(INT32 value) //Could this be Atomic?
                {
                    _m_value = value;
                    return *this;
                }

                // Atomic APIs
                inline INT32 assign(INT32 value)
                {
                    return AtomicIntegerSet32(&_m_value, value);
                }

                inline INT32 add(INT32 value)
                {
                    return AtomicIntegerFetchAdd32(&_m_value, value);
                }

                inline INT32 subtract(INT32 value)
                {
                    return AtomicIntegerFetchAdd32(&_m_value, -value);
                }

                inline INT32 increment()
                {
                    return AtomicIntegerFetchAdd32(&_m_value, 1);
                }

                inline INT32 decrement()
                {
                    return AtomicIntegerFetchAdd32(&_m_value, -1);
                }

                inline INT32 and(INT32 value)
                {
                    return AtomicIntegerAnd32(&_m_value, value);
                }

                inline INT32 xor(INT32 value)
                {
                    return AtomicIntegerXor32(&_m_value, value);
                }

                inline INT32 or(INT32 value)
                {
                    return AtomicIntegerOr32(&_m_value, value);
                }

                inline INT32 compareAndSet(INT32 comparand, INT32 newValue)
                {
                    return AtomicIntegerCompareAndSet32(&_m_value,comparand,newValue);
                }

            protected:
                M_ATOMIC INT32 _m_value;
                
            };

            class CAtomicUnsignedInteger32
            {
            public:
                inline CAtomicUnsignedInteger32() {}
                inline CAtomicUnsignedInteger32(UINT32 v) { _m_value = v; }

                // Non-atomic APIs
                inline bool operator==(UINT32 value) const
                {
                    return _m_value == value;
                }

                inline bool operator!=(UINT32 value) const
                {
                    return _m_value != value;
                }

                inline bool operator!() const
                {
                    return _m_value == 0;
                }

                inline operator UINT32() const
                {
                    return _m_value;
                }

                inline CAtomicUnsignedInteger32& operator=(UINT32 value) //Could this be Atomic?
                {
                    _m_value = value;
                    return *this;
                }

                // Atomic APIs
                inline UINT32 assign(UINT32 value)
                {
                    return AtomicIntegerSet32(&_m_value, value);
                }

                inline UINT32 add(UINT32 value)
                {
                    return AtomicIntegerFetchAdd32(&_m_value, value);
                }

                inline UINT32 subtract(UINT32 value)
                {
                    return AtomicIntegerFetchAdd32(&_m_value, (LONG)0-value);
                }

                inline UINT32 increment()
                {
                    return AtomicIntegerFetchAdd32(&_m_value, 1);
                }

                inline UINT32 decrement()
                {
                    return AtomicIntegerFetchAdd32(&_m_value, -1);
                }

                inline UINT32 and(UINT32 value)
                {
                    return AtomicIntegerAnd32(&_m_value, value);
                }

                inline UINT32 xor(UINT32 value)
                {
                    return AtomicIntegerXor32(&_m_value, value);
                }

                inline UINT32 or(UINT32 value)
                {
                    return AtomicIntegerOr32(&_m_value, value);
                }

                inline UINT32 compareAndSet(UINT32 comparand, UINT32 newValue)
                {
                    return AtomicIntegerCompareAndSet32(&_m_value,comparand,newValue);
                }

            protected:
                M_ATOMIC UINT32 _m_value;

            };

            class CAtomicInteger64
            {
            public:
                // Non-atomic APIs

                inline CAtomicInteger64() {}
                inline CAtomicInteger64(INT64 v) { _m_value = v; }

                inline bool operator==(INT64 value) const
                {
                    return _m_value == value;
                }

                inline bool operator!=(INT64 value) const
                {
                    return _m_value != value;
                }

                inline bool operator!() const
                {
                    return _m_value == 0;
                }

                inline operator INT64() const
                {
                    return _m_value;
                }

                inline CAtomicInteger64 &operator=(INT64 value) //Could this be Atomic?
                {
                    _m_value = value;
                    return *this;
                }

                // Atomic APIs
                inline INT64 assign(INT64 value)
                {
                    return AtomicIntegerSet64(&_m_value, value);
                }

                inline INT64 add(INT64 value)
                {
                    return AtomicIntegerFetchAdd64(&_m_value, value);
                }

                inline INT64 subtract(INT64 value)
                {
                    return AtomicIntegerFetchAdd64(&_m_value, -value);
                }

                inline INT64 increment()
                {
                    return AtomicIntegerFetchAdd64(&_m_value, 1);
                }

                inline INT64 decrement()
                {
                    return AtomicIntegerFetchAdd64(&_m_value, -1);
                }

                inline INT64 and(INT64 value)
                {
                    return AtomicIntegerAnd64(&_m_value, value);
                }

                inline INT64 xor(INT64 value)
                {
                    return AtomicIntegerXor64(&_m_value, value);
                }

                inline INT64 or(INT64 value)
                {
                    return AtomicIntegerOr64(&_m_value, value);
                }

                inline INT64 compareAndSet(INT64 comparand, INT64 newValue)
                {
                    return AtomicIntegerCompareAndSet64(&_m_value,comparand,newValue);
                }

            protected:
                M_ATOMIC INT64 _m_value;

            };

            class CAtomicUnsignedInteger64
            {
            public:
                inline CAtomicUnsignedInteger64() {}
                inline CAtomicUnsignedInteger64(UINT64 v) { _m_value = v; }

                // Non-atomic APIs
                inline bool operator==(UINT64 value) const
                {
                    return _m_value == value;
                }

                inline bool operator!=(UINT64 value) const
                {
                    return _m_value != value;
                }

                inline bool operator!() const
                {
                    return _m_value == 0;
                }

                inline operator UINT64() const
                {
                    return _m_value;
                }

                inline CAtomicUnsignedInteger64& operator=(UINT64 value) //Could this be Atomic?
                {
                    _m_value = value;
                    return *this;
                }

                // Atomic APIs
                inline UINT64 assign(UINT64 value)
                {
                    return AtomicIntegerSet64(&_m_value, value);
                }

                inline UINT64 add(UINT64 value)
                {
                    return AtomicIntegerFetchAdd64(&_m_value, value);
                }

                inline UINT64 subtract(UINT64 value)
                {
                    return AtomicIntegerFetchAdd64(&_m_value, (LONG)0-value);
                }

                inline UINT64 increment()
                {
                    return AtomicIntegerFetchAdd64(&_m_value, 1);
                }

                inline UINT64 decrement()
                {
                    return AtomicIntegerFetchAdd64(&_m_value, -1);
                }

                inline UINT64 and(UINT64 value)
                {
                    return AtomicIntegerAnd64(&_m_value, value);
                }

                inline UINT64 xor(UINT64 value)
                {
                    return AtomicIntegerXor64(&_m_value, value);
                }

                inline UINT64 or(UINT64 value)
                {
                    return AtomicIntegerOr64(&_m_value, value);
                }

                inline UINT64 compareAndSet(UINT64 comparand, UINT64 newValue)
                {
                    return AtomicIntegerCompareAndSet64(&_m_value,comparand,newValue);
                }

            protected:
                M_ATOMIC UINT64 _m_value;

            };

        }

    }    
}

